{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from Huffman_Code import Huffuman_encode_2\n",
    "from collections import Counter\n",
    "\n",
    "import random\n",
    "import time\n",
    "import hashlib\n",
    "import secrets\n",
    "import string\n",
    "import copy\n",
    "\n",
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[136 137 138 ... 147 130  97]\n",
      " [136 137 137 ... 148 131  97]\n",
      " [136 137 137 ... 147 132  98]\n",
      " ...\n",
      " [ 20  22  26 ...  69  67  65]\n",
      " [ 20  23  27 ...  71  70  71]\n",
      " [ 22  25  30 ...  70  71  75]]\n"
     ]
    }
   ],
   "source": [
    "from PIL import Image\n",
    "\n",
    "# Open the image file\n",
    "image = Image.open('Lena_512.jpg')\n",
    "\n",
    "# Convert the image to a NumPy array\n",
    "image_array = np.array(image)\n",
    "\n",
    "# Now you have the image data in a NumPy array\n",
    "print(image_array)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "Original_Image_X = np.array([[1, 3, 1, 3],\n",
    "                            [0, 1, 1, 0],\n",
    "                            [0, 2, 2, 2],\n",
    "                            [3, 3, 4, 3]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TV_HCT():\n",
    "    def __init__(self, image_X) -> None:\n",
    "        self.Image_X = image_X\n",
    "        self.W = len(image_X[:, 0])\n",
    "        self.H = len(image_X[0])\n",
    "        self.SUM_all = self.W * self.H\n",
    "        self.User_Key = None\n",
    "        self.generate_secret_key()\n",
    "\n",
    "        self.Initial_HCT = None\n",
    "        self.Error_Map = None\n",
    "        self.Original_Sequence = None\n",
    "        self.Shuffled_Sequence = None\n",
    "        self.M = None\n",
    "        self.V = None\n",
    "        self.CCS_C = None\n",
    "    #随机生成Ku\n",
    "    def generate_secret_key(self, length=16):\n",
    "        # Generate a secret key of length 16\n",
    "        alphabet = string.ascii_letters + string.digits + string.punctuation\n",
    "        secret_key = ''.join(secrets.choice(alphabet) for _ in range(length))\n",
    "        print('User_Key:', secret_key)\n",
    "        self.User_Key = secret_key\n",
    "    #在index class scrambling中计算Tb时需要使用\n",
    "    def Dec2Bin(self, dec, length):\n",
    "        BIN = ''\n",
    "        if(dec < 0): # If it is negative.\n",
    "            dec = abs(dec)\n",
    "            BIN = bin(dec).replace('0b', '')\n",
    "            BIN = '1' + '0' * (length - len(BIN) - 1) + BIN\n",
    "        else:\n",
    "            BIN = bin(dec).replace('0b', '')\n",
    "            BIN = '0' * (length - len(BIN)) + BIN\n",
    "        return BIN\n",
    "    '''这个函数的功能是将一个十进制数转换为指定长度的二进制数。\n",
    "    1. 函数名为 Dec2Bin，它接受三个参数:self、dec(要转换的十进制数)、length(指定的二进制数的长度）。\n",
    "    2. 首先，函数会定义一个变量 BIN 用于存储最终的二进制数。然后，函数会检查输入的十进制数是否为负数，如果是负数，则将其转换为正数，并且在转换成二进制之后，在最高位加上一个 '1'，以表示这是一个负数的补码表示。\n",
    "    3. 如果输入的十进制数为正数，则直接将其转换为二进制表示，并在高位补充0，使得二进制数的长度达到指定的长度。\n",
    "    4. 最后，函数返回转换得到的二进制数 BIN。'''\n",
    "\n",
    "    #预测误差图\n",
    "    def Prediction_Error_Map(self):\n",
    "        def MED(a, b, c):\n",
    "            value = 0\n",
    "            if(a >= max(b, c)):\n",
    "                value = min(b, c)\n",
    "            elif(a <= min(b, c)):\n",
    "                value = max(b, c)\n",
    "            else:\n",
    "                value = b + c - a\n",
    "            return value\n",
    "        image = self.Image_X\n",
    "        error_map = np.zeros_like(self.Image_X)\n",
    "        for i in range(self.W):\n",
    "            for j in range(self.H):\n",
    "                if(i == 0 and j == 0):\n",
    "                    error_map[i][j] = image[i][j]\n",
    "                elif(i == 0 and j > 0):\n",
    "                    error_map[i][j] = image[i][j] - image[i][j - 1]\n",
    "                elif(i > 0 and j == 0):\n",
    "                    error_map[i][j] = image[i][j] - image[i - 1][j]\n",
    "                else:\n",
    "                    error_map[i][j] = image[i][j] - MED(image[i - 1][j - 1], \n",
    "                                                        image[i][j - 1], \n",
    "                                                        image[i - 1][j])\n",
    "        self.Error_Map = error_map\n",
    "        print('error_map:', error_map)\n",
    "    #生成时变哈夫曼编码\n",
    "    def Huffman_Code(self):\n",
    "        error_map_vector = list(np.reshape(self.Error_Map, [-1]))\n",
    "        counter = dict(Counter(error_map_vector))\n",
    "        self.Error_Map_Vector = error_map_vector\n",
    "        self.M = len(counter) # M: the number of categories U\n",
    "        self.U = list(counter.keys())#存储U的数组（生成Tb时需要用）\n",
    "        print('counter:', counter)\n",
    "\n",
    "        source = []\n",
    "        for item in counter:\n",
    "            name = str(item)\n",
    "            probability = counter[item] / self.SUM_all\n",
    "            element = [name, probability]\n",
    "            source.append(element)\n",
    "        print('source:', source)\n",
    "        #生成哈夫曼编码\n",
    "        huffman = Huffuman_encode_2(source, self.SUM_all)\n",
    "\n",
    "        # [Index, label(U), num(N), code length(s), code(W)]\n",
    "        initial_HCT = huffman.Huffuman_code\n",
    "        self.Initial_HCT = initial_HCT\n",
    "        print('initial_HCT:', self.Initial_HCT)\n",
    "        copy_initial_HCT = copy.deepcopy(initial_HCT)\n",
    "\n",
    "        # Initial_HCT_Label_Dict——》'label(U)': [index, num(N), code length(s), code(W)]\n",
    "        initial_HCT_label_dict = {}\n",
    "        for item in copy_initial_HCT:\n",
    "            label = item[1]\n",
    "            item.pop(1)\n",
    "            initial_HCT_label_dict[int(label)] = item\n",
    "        print('initial_HCT_dict:', initial_HCT_label_dict)\n",
    "        self.Initial_HCT_Label_Dict = initial_HCT_label_dict\n",
    "    \n",
    "    #类内置乱\n",
    "    #str(time.time())就代表Kt；in_class_srambling中的置换数组V就由Kt生成（由于论文没有说明确的生成方法，我们就找了主流的生成方法\n",
    "    def In_Class_Scrambling(self):\n",
    "        '''第一步'''\n",
    "        def Shuffling(List):#传入待打乱的序列\n",
    "            # User key\n",
    "            user_key = self.User_Key\n",
    "            # 用时间戳和Ku生成密钥串\n",
    "            combined_string = str(time.time()) + user_key\n",
    "            # 用哈希算法加密\n",
    "            hashed_seed = hashlib.sha256(combined_string.encode()).hexdigest()\n",
    "            # Convert the hashed seed to an integer\n",
    "            seed_int = int(hashed_seed, 16)  # Convert hexadecimal hash to integer\n",
    "            # Use the seed to initialize the random number generator\n",
    "            random.seed(seed_int)\n",
    "            # 用加密好的密钥来打乱传入的List\n",
    "            shuffled_list = [random.sample(sub_list, len(sub_list)) for sub_list in List]\n",
    "            return shuffled_list\n",
    "        '''第二步'''\n",
    "        #通过打乱后的V数组+哈希编码 生成CCS\n",
    "        def Create_CCS_C():\n",
    "            CCS = ''\n",
    "            initial_HCT_dict = self.Initial_HCT_Label_Dict\n",
    "            for error_value in self.Error_Map_Vector:\n",
    "                origin_index = initial_HCT_dict[error_value][0] # Start with 1.\n",
    "                # print(origin_index)\n",
    "                scrambled_index = mapping_dict[origin_index]\n",
    "                # print(scrambled_index)\n",
    "                CCS = CCS + initiaL_HCT[scrambled_index - 1][4]\n",
    "            print('CCS:', CCS)\n",
    "            self.CCS_C = CCS\n",
    "            self.length_C = len(CCS)\n",
    "            print('lc:', self.length_C)\n",
    "        '''第三步：调用函数生成in-class scrambling中的ccs'''\n",
    "        initiaL_HCT = self.Initial_HCT\n",
    "        Number_Sequence = [item[2] for item in initiaL_HCT] + [None]\n",
    "        print('Number_Sequence:', Number_Sequence)\n",
    "        original_sequence = []\n",
    "\n",
    "        index = 1\n",
    "        temp = []\n",
    "        for i in range(self.M):\n",
    "            if(Number_Sequence[i + 1] == Number_Sequence[i]):\n",
    "                temp.append(index)\n",
    "            else:\n",
    "                temp.append(index)\n",
    "                original_sequence.append(temp)\n",
    "                temp = []\n",
    "            index += 1\n",
    "        print('original_sequence:', original_sequence)\n",
    "        self.Original_Sequence = original_sequence\n",
    "        shuffled_sequence = Shuffling(original_sequence)\n",
    "        print('shuffled_sequence:', shuffled_sequence)\n",
    "        self.Shuffled_Sequence = shuffled_sequence # Shuffled Sequence\n",
    "\n",
    "        # 把二维矩阵变为一维矩阵\n",
    "        origin_list = [item for sublist in original_sequence for item in sublist]\n",
    "        shuffled_list = [item for sublist in shuffled_sequence for item in sublist]\n",
    "        mapping_dict = {}\n",
    "        for origin, shuffling in zip(origin_list, shuffled_list):\n",
    "            mapping_dict[origin] = shuffling\n",
    "        print('mapping_dict:', mapping_dict)\n",
    "\n",
    "        self.V = str(shuffled_sequence).replace('[', '').replace(']', '').replace(',', '').replace(' ', '')\n",
    "        print('V:', self.V)\n",
    "\n",
    "        Create_CCS_C()\n",
    "\n",
    "    #（最后一次新加）在index class scrambling中计算Ke需要用到（Tb生成过程较复杂）\n",
    "    def Tb_generate(self):\n",
    "        #M（U的种类数）转化为二进制\n",
    "        def First_step():\n",
    "            STRING = ''\n",
    "            STRING = self.Dec2Bin(self.M, 9)\n",
    "            return STRING\n",
    "        #将U中每个元素转化为二进制\n",
    "        def Second_step():\n",
    "            STRING = ''\n",
    "            for u_k in self.U:\n",
    "                Bin = self.Dec2Bin(u_k, 9)\n",
    "                STRING = STRING + Bin#拼一起\n",
    "            return STRING\n",
    "        #哈夫曼编码的个数的二进制表示+各个编码\n",
    "        def Thrid_step():\n",
    "            #Initial_HCT_Label_Dict——》'label(U)': [index, num(N), code length(s), code(W)]\n",
    "            label_dict = self.Initial_HCT_Label_Dict\n",
    "            STRING = ''\n",
    "            #code是字典中的每个key\n",
    "            for code in label_dict:\n",
    "                codelength_string = self.Dec2Bin(label_dict[code][2], 8)\n",
    "                codeword = label_dict[code][3]\n",
    "                STRING = STRING + (codelength_string + codeword)\n",
    "            return STRING\n",
    "\n",
    "        # original_seq = self.Original_Sequence\n",
    "        # shuffled_seq = self.Shuffled_Sequence\n",
    "        first_string = First_step()\n",
    "        second_string = Second_step()\n",
    "        third_string = Thrid_step()\n",
    "        Tb = first_string + second_string + third_string\n",
    "        self.T_b = Tb\n",
    "        print('Tb:', Tb)\n",
    "        self.length_T = len(Tb)\n",
    "    #index置乱核心代码\n",
    "    def Index_Class_Scrambling(self):\n",
    "        def g_generate():\n",
    "            # 生成g\n",
    "            Lc = self.length_C\n",
    "            x = random.random()\n",
    "            len1 = Lc / 30\n",
    "            # G = math.ceil(x * len1)\n",
    "            G = 5\n",
    "            self.G = G\n",
    "            print(\"G个分组:\", G)\n",
    "\n",
    "            # 构建一个生成每个分组中有几个元素的算法\n",
    "            result1 = np.random.permutation(Lc - 1)[:(G - 1)] # 生成1到Lc - 1之间的G - 1个随机数\n",
    "            result1 = np.sort(result1)  # 对结果进行排序，使其递增，这样生成的g才没有负数\n",
    "            # print(\"randperm:\", result1)\n",
    "            result2 = np.insert(result1, 0, 0)\n",
    "            result3 = np.append(result2, Lc)\n",
    "            g = np.diff(result3)\n",
    "            self.g = g\n",
    "            print('max(g):', max(g))\n",
    "            print(\"g(每个分组中需要包含的元素个数):\", g)\n",
    "\n",
    "            return g\n",
    "        #Ke=Hash(Ku,Tb)\n",
    "        def Ke_generate():\n",
    "            # 生成ke\n",
    "            user_key = self.User_Key\n",
    "            combined_str = user_key + self.T_b\n",
    "            # 用hash函数\n",
    "            Ke = hashlib.sha256(combined_str.encode()).hexdigest()\n",
    "            self.K_e = Ke\n",
    "            print('Ke:', Ke)\n",
    "            return Ke\n",
    "        #Ψ=hash(Ku.Tb) （论文没有明确说Ψ的生成算法）\n",
    "        def Psi_generate(length_of_index_C): \n",
    "            # 生成Ψ，注意是从1开始\n",
    "            sequence = [i for i in range(1, length_of_index_C + 1)]\n",
    "            ke = Ke_generate()\n",
    "\n",
    "            hashed_seed = hashlib.sha256(ke.encode()).hexdigest()\n",
    "            seed_int = int(hashed_seed, 16)\n",
    "            random.seed(seed_int)\n",
    "            shuffled_list = random.sample(sequence, len(sequence))\n",
    "            \n",
    "            return shuffled_list\n",
    "\n",
    "        # 生成index group C\n",
    "        start = 0\n",
    "        groupC = []\n",
    "        g = g_generate()\n",
    "        CCS = self.CCS_C\n",
    "        for grouplength in g:\n",
    "            group = CCS[start : (start + grouplength)]\n",
    "            groupC.append(group)\n",
    "            start += grouplength\n",
    "        print('GroupC:', groupC)\n",
    "        self.Group_C = groupC\n",
    "\n",
    "        # 生成index class\n",
    "        IndexClass = [''] * max(g)#是否改为len(g)\n",
    "        for strCCS in groupC:\n",
    "            j = 0\n",
    "            for bit in strCCS:\n",
    "                IndexClass[j] += bit\n",
    "                j = j + 1\n",
    "        print(\"IndexClass:\", IndexClass)\n",
    "        self.Index_Class_C = IndexClass\n",
    "\n",
    "        # 建立映射表，键为索引，值为对应的字符串\n",
    "        IndexClass_mapping = {}\n",
    "        index = 1\n",
    "        for stringg in IndexClass:\n",
    "            IndexClass_mapping[index] = stringg\n",
    "            index += 1\n",
    "\n",
    "        psi = Psi_generate(max(g)) # 生成映射表和Ψ\n",
    "        print('psi:', psi)\n",
    "        scrambled_index_class = []\n",
    "        for scrambled_index in psi:\n",
    "            scrambled_index_class.append(IndexClass_mapping[scrambled_index]) # 把对应的字符串添加进去\n",
    "        print('scrambled_index_class:', scrambled_index_class)\n",
    "\n",
    "        # 合成E\n",
    "        E = ''\n",
    "        for strr in scrambled_index_class:\n",
    "            E += strr\n",
    "        print('E:', E)\n",
    "        print('len(E):', len(E))\n",
    "        self.E = E"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "User_Key: .8>{5t&h;`*e*7/'\n",
      "error_map: [[ 1  2 -2  2]\n",
      " [-1 -1  0 -3]\n",
      " [ 0  1  0  1]\n",
      " [ 3  0  1 -1]]\n",
      "counter: {1: 4, 2: 2, -2: 1, -1: 3, 0: 4, -3: 1, 3: 1}\n",
      "source: [['1', 0.25], ['2', 0.125], ['-2', 0.0625], ['-1', 0.1875], ['0', 0.25], ['-3', 0.0625], ['3', 0.0625]]\n",
      "initial_HCT: [[1, '1', 4, 2, '01'], [2, '0', 4, 2, '10'], [3, '-1', 3, 2, '11'], [4, '2', 2, 3, '001'], [5, '-2', 1, 4, '0001'], [6, '-3', 1, 5, '00000'], [7, '3', 1, 5, '00001']]\n",
      "initial_HCT_dict: {1: [1, 4, 2, '01'], 0: [2, 4, 2, '10'], -1: [3, 3, 2, '11'], 2: [4, 2, 3, '001'], -2: [5, 1, 4, '0001'], -3: [6, 1, 5, '00000'], 3: [7, 1, 5, '00001']}\n",
      "Number_Sequence: [4, 4, 3, 2, 1, 1, 1, None]\n",
      "original_sequence: [[1, 2], [3], [4], [5, 6, 7]]\n",
      "shuffled_sequence: [[2, 1], [3], [4], [6, 5, 7]]\n",
      "mapping_dict: {1: 2, 2: 1, 3: 3, 4: 4, 5: 6, 6: 5, 7: 7}\n",
      "V: 2134657\n",
      "CCS: 100010000000111110100010110011000001011011\n",
      "lc: 42\n",
      "Tb: 0000001110000000010000000101000000101000000010000000001000000110000000110000001001000000101000000010110000001100100000100000100000101000000000010100001\n",
      "G个分组: 5\n",
      "max(g): 17\n",
      "g(每个分组中需要包含的元素个数): [ 7 17 10  6  2]\n",
      "GroupC: ['1000100', '00000111110100010', '1100110000', '010110', '11']\n",
      "IndexClass: ['10101', '00111', '0000', '0001', '1011', '0110', '010', '10', '10', '10', '0', '1', '0', '0', '0', '1', '0']\n",
      "Ke: af4007b425c860adcad630ff3b80f51840b32d2125995d8de91af52c5fa5d29a\n",
      "psi: [8, 12, 2, 4, 5, 10, 16, 9, 3, 13, 17, 15, 6, 11, 1, 7, 14]\n",
      "scrambled_index_class: ['10', '1', '00111', '0001', '1011', '10', '1', '10', '0000', '0', '0', '0', '0110', '0', '10101', '010', '0']\n",
      "E: 101001110001101110110000000001100101010100\n",
      "len(E): 42\n"
     ]
    }
   ],
   "source": [
    "tv_hct = TV_HCT(Original_Image_X)\n",
    "tv_hct.Prediction_Error_Map()\n",
    "tv_hct.Huffman_Code()\n",
    "tv_hct.In_Class_Scrambling()\n",
    "tv_hct.Tb_generate()\n",
    "tv_hct.Index_Class_Scrambling()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
